/**
 * 文件管理路由
 *
 * Created by snowingsea on 2020/02/17.
 */
// const multer = require('multer');
const { ObjectID } = require('mongodb');
const { Types } = require('mongoose');
const path = require('path');
const fs = require('fs-extra');
const middleware = require('./../middleware');
const files = require('./../../models/files');
const tasks = require('./../../models/tasks');
const PhoenixError = require('./../../models/phoenix-error');
const ProjectVersion = require('../../models/mongo/project-version');
const defects = require('../../models/defects');
const common = require('../../models/common');
const rulesModel = require('../../models/rules');
const licenseModel = require('../../models/license');
// const cacheUtil = require('../../cacheUtil');
const utility = require('../../models/utility');
const uploadProgress = require('../middleware/upload-progress');
const runtimeChecks = require('../../models/runtime-check');
/**
 * 解析源码
 * @param req
 * @param res
 * @param next
 */
function parseFiles(req, res, next) {
  if (!req.$compilingFiles || req.$compilingFiles.length === 0) {
    next(new PhoenixError('No file to parse'));
    return;
  }
  tasks.addParseTask(req.$files, req.$compilingFiles, req.$project, req.$projectVersion, req.$me)
    .then((task) => {
      if (!task) {
        next(new PhoenixError('invalid request', 'No file to parse'));
      } else {
        res.status(202).json(tasks.getJson(task));
      }
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

/**
 * 静态分析
 * @param req
 * @param res
 * @param next
 */

function analyseFiles(req, res, next) {
  (async () => {
    const { fileIds } = req.body;
    const { projectVersionId } = req.params;
    // 选择文件分析
    if (!fileIds || fileIds.length === 0) {
      throw new PhoenixError('invalid request', 'Missing parameters. fileIds is required');
    }
    // 更新对应回归版本状态
    await ProjectVersion.updateOne({ _id: ObjectID(projectVersionId) }, {
      $set: {
        regressionStatus: 0,
      },
    });
    // 获取待解析的文件
    const waitAnalyseFiles = (await files.getFiles(
      projectVersionId,
      { fileIds },
      { extensions: req.body.extensions || null, kinds: files.kind.file }
    )).filter((file) => !global.config.fileFilters.includes(file.fileName) && (
      !file.shieldFilesCount
      || Object.keys(file.shieldFilesCount).length === 0
      || file.shieldFilesCount[common.renameMongoKey(file.extname)] === 0
    ));
    const licenseRuleSets = await licenseModel.getStaticAnalyzeRuleSetByLicense();
    const templateRuleSets = (await rulesModel.getRuleSetsByTemplateId(
      req.$projectVersion.analyzeTemplate
    )).filter((ruleSet) => licenseRuleSets.includes(ruleSet.ruleSetName))
      .map((ruleSet) => ruleSet.ruleSetName);

    if (templateRuleSets.length === 0) {
      throw new PhoenixError('invalid request', 'No ruleSet to analyse');
    }
    req.$projectVersion.specs = templateRuleSets;
    let task;
    if (waitAnalyseFiles.length > 0 && templateRuleSets.length > 0) {
      // 清除选择的文件的缺陷和重置统计结果
      await Promise.all([
        defects.clearFilesDefects(projectVersionId, null, waitAnalyseFiles),
        defects.clearAllRuleStatistics(projectVersionId),
      ]);
      await ProjectVersion.updateOne({ _id: projectVersionId }, { specs: templateRuleSets });
      task = await tasks.addAnalyzeTask(waitAnalyseFiles, req.$compilingFiles, req.$project, req.$projectVersion, req.$me);
    }
    if (!task) {
      throw new PhoenixError('invalid request', 'No file to analyse');
    } else {
      res.status(202).json(tasks.getJson(task));
    }
  })().catch((err) => {
    next(new PhoenixError(err));
  });
}
/**
 * 一键回归
 * @param req
 * @param res
 * @param next
 */
function analyzeRegressionFiles(req, res, next) {
  (async () => {
    // 检测老版本是否存在
    const { fileIds } = req.body;
    const { projectVersionId } = req.params;
    const regressionVersion = await ProjectVersion.findById(ObjectID(projectVersionId));
    const originalVersion = await ProjectVersion.findById(ObjectID(regressionVersion.oldVersionId));
    if (!originalVersion) {
      throw new PhoenixError('originalVersion not found');
    }
    if (!fileIds || fileIds.length === 0) {
      throw new PhoenixError('invalid request', 'Missing parameters. fileIds is required');
    }
    let analyseFiles = await files.getFiles(
      projectVersionId,
      { fileIds },
      { extensions: req.body.extensions || null, kinds: files.kind.file }
    );
    analyseFiles = analyseFiles.filter((file) => (!global.config.fileFilters || global.config.fileFilters.indexOf(file.fileName) < 0)
        && (Object.keys(file.shieldFilesCount).length === 0 || file.shieldFilesCount[common.renameMongoKey(file.extname)] === 0));
    if (analyseFiles.length === 0) {
      throw new PhoenixError('invalid request', 'No file to analyse');
    }
    const licenseRuleSets = await licenseModel.getStaticAnalyzeRuleSetByLicense();
    const templateRuleSets = (await rulesModel.getRuleSetsByTemplateId(
      req.$projectVersion.analyzeTemplate
    )).filter((ruleSet) => licenseRuleSets.includes(ruleSet.ruleSetName))
      .map((ruleSet) => ruleSet.ruleSetName);
    if (templateRuleSets.length === 0) {
      throw new PhoenixError('invalid request', 'No ruleSet to analyse');
    }
    req.$projectVersion.specs = templateRuleSets;
    // 清除选择的文件的缺陷
    await defects.clearFilesDefects(projectVersionId, null, analyseFiles);
    const task = await tasks.addRegressionAnalyzeTask(analyseFiles, req.$project, req.$projectVersion, req.$me);
    if (!task) {
      throw new PhoenixError('invalid request', 'No file to analyse');
    }
    await ProjectVersion.updateOne({ _id: ObjectID(projectVersionId) }, {
      $set: {
        regressionStatus: 1,
      },
    });
    res.status(202).json(tasks.getJson(task));
  })().catch((err) => {
    next(new PhoenixError(err));
  });
}

/**
 * 获取文件编译信息
 * @param req
 * @param res
 * @param next
 */
function getFileDiag(req, res, next) {
  const { fileId } = req.params;
  files.getDiag(fileId)
    .then((result) => {
      const diagMessages = result ? result.diagMessages : [];
      res.json({
        fileId,
        diag: diagMessages || [],
      });
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

/**
 * 获取类型系统
 * @param req
 * @param res
 * @param next
 */
function getTypes(req, res, next) {
  const { fileId } = req.params;
  files.getTypes(fileId)
    .then((result) => {
      res.json(files.getTypesJson(fileId, result));
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

function getTypeNames(req, res, next) {
  (async () => {
    const { fileId } = req.params;
    const [fileTypes] = await files.getTypeNames(fileId);
    if (!fileTypes) {
      throw new PhoenixError('not found', `not found type system of file id ${fileId}`);
    }
    res.json(fileTypes.types);
  })()
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

/**
 * 获取全局变量
 * @param req
 * @param res
 * @param next
 */
function getGlobalVariables(req, res, next) {
  const { fileId } = req.params;
  files.getGlobalVariables(fileId)
    .then((result) => {
      const globals = result ? result.globals : {};
      res.json({
        fileId,
        globals: globals || {},
      });
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

/**
 * 获取字面量
 * @param req
 * @param res
 * @param next
 */
function getLiterals(req, res, next) {
  const { fileId } = req.params;
  files.getLiterals(fileId)
    .then((result) => {
      const literals = result ? result.literals : [];
      res.json({
        fileId,
        literals: literals || [],
      });
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

function getMacros(req, res, next) {
  const { fileId } = req.params;
  files.getMacros(fileId)
    .then((result) => {
      const macros = result ? result.macros : [];
      res.json({
        fileId,
        macros: macros || [],
      });
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

/**
 * 项目总览-文件列表
 * @param req
 * @param res
 * @param next
 */
function allFilesOverview(req, res, next) {
  (async () => {
    const { projectVersionId: versionId } = req.params;
    const {
      status, sortBy, order, type,
    } = req.query;
    let { page, perPage } = req.query;
    let extensions;
    if (type) {
      const projectVersion = await ProjectVersion.findById(ObjectID(versionId));
      switch (type) {
        case 'source':
        {
          extensions = Object.values(projectVersion.languages)
            .reduce((arr, item) => arr.concat(item.suffixes), []);
          break;
        }
        case 'header':
        {
          extensions = projectVersion.headers.suffixes;
          break;
        }

        default:
          throw new PhoenixError('invalid request', 'type can only be source or header');
      }
    }

    page = parseInt(page, 10) || 1;
    perPage = parseInt(perPage, 10) || 100;
    const [list, total] = await files.getOverview(versionId, {
      extensions,
      status,
      page,
      pageSize: perPage,
      sortBy,
      order,
    });
    const countOverview = await files.fileCountOverview(versionId, {
      extensions,
    });
    const version = await ProjectVersion.findById(Types.ObjectId(versionId), [
      'projectId', 'versionName', 'coverages',
    ], { lean: true });
    version.projectName = req.$project.projectName;
    res.json({
      version,
      files: list,
      countOverview,
      pagination: {
        total,
        page,
        perPage,
        sortBy,
        order,
      },
    });
  })()
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

/**
 * 项目信息总览-文件列表下载xlsx文件
 * @param req
 * @param res
 * @param next
 */
function exportFilesOverview(req, res, next) {
  (async () => {
    const { projectVersionId: versionId } = req.params;
    const { type } = req.query;
    let extensions;
    let excelName;
    // middleware
    const projectVersion = await ProjectVersion.findById(ObjectID(versionId));
    if (type) {
      switch (type) {
        case 'source':
        {
          extensions = Object.values(projectVersion.languages)
            .reduce((arr, item) => arr.concat(item.suffixes), []);
          excelName = req.$project.projectName.concat(' ').concat(req.$projectVersion.versionName).concat('.源文件列表.xlsx');
          break;
        }
        case 'header':
        {
          extensions = projectVersion.headers.suffixes;
          excelName = req.$project.projectName.concat(' ').concat(req.$projectVersion.versionName).concat('.头文件列表.xlsx');
          break;
        }

        default:
          throw new PhoenixError('invalid request', 'type can only be source or header');
      }
    } else {
      throw new PhoenixError('invalid request', 'missing type attribute');
    }
    const [xlsxFilePath, cachePath] = await files.generateOverviewXlsx(versionId, extensions, projectVersion.coverages, excelName, req.$locale);
    res.setHeader('Access-Control-Expose-Headers', 'Content-Disposition');
    res.download(xlsxFilePath, encodeURI(path.basename(xlsxFilePath)), () => fs.remove(cachePath));
  })()
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

function getDefectsRules(req, res, next) {
  (async () => {
    const { fileId } = req.params;
    const { level } = req.query;
    const levels = level ? [].concat(level).map((l) => parseInt(l, 10)) : undefined;
    const ret = await defects.getFilesRuleDefectsCount(fileId, {
      levels,
      versionId: req.$projectVersion._id,
    });
    res.json({
      rules: ret,
    });
  })()
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

function resetFile(req, res, next) {
  const { fileId } = req.params;
  files.resetFileOrDirectory(fileId, req.$file)
    .then(() => res.status(204).json())
    .catch((err) => {
      next(new PhoenixError(err));
    });
}
/**
 * 屏蔽文件
 * @param {*} req
 * @param {*} res
 * @param {*} next
 */
function shieldFiles(req, res, next) {
  (async () => {
    const status = parseInt(req.query.status, 10);
    await files.shieldFiles(req.params.fileId, status);
    res.status(201).json();
  })().catch((err) => {
    next(new PhoenixError(err));
  });
}

function createDirectories(req, res, next) {
  const paths = req.body;
  let pathStr = '.';
  let directoryId = req.$projectVersion.rootDirectoryId;
  let fileInstance = req.$projectVersion.rootDirectory;
  utility.arrayChunkOperation(paths, 1, (item) => {
    pathStr = path.join(pathStr, item);
    return files.getFileByPath(req.$projectVersion._id, pathStr)
      .then((file) => {
        if (file) {
          directoryId = file._id;
          fileInstance = file;
          return Promise.resolve();
        }
        return files.addFile2Directory(
          directoryId,
          { kind: files.kind.directory, fileName: item },
          fileInstance,
          req.$projectVersion,
          req.$project,
          req.$project.creator
        )
          .then((res) => {
            directoryId = res._id;
            fileInstance = res;
          });
      });
  })
    .then(() => {
      res.json({ directoryId });
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}

function updateFileEncoding(req, res, next) {
  const { encoding } = req.body;
  files.updateEncoding(req.$file._id, encoding)
    .then(() => {
      req.$file.encoding = encoding;
      next();
    })
    .catch((err) => {
      next(new PhoenixError(err));
    });
}
function runTimeCheck(req, res, next) {
  (async () => {
    const sourceFileExtnames = [];
    const { languages, headers } = req.$projectVersion;
    if (languages) {
      Object.keys(languages).forEach((key) => {
        if (languages[key].suffixes) {
          sourceFileExtnames.push(...languages[key].suffixes);
        }
      });
    }
    if (headers && headers.suffixes) {
      sourceFileExtnames.push(...headers.suffixes);
    }
    const task = await runtimeChecks.runTimeCheck(sourceFileExtnames, req.$project, req.$projectVersion, req.$me, req.body.ruleIds);
    if (!task) {
      throw new PhoenixError('create task failed.');
    }
    res.json({ taskId: task._id });
  })().catch((err) => {
    next(new PhoenixError(err));
  });
}
function getRuntimeCheckResult(req, res, next) {
  (async () => {
    const result = await runtimeChecks.getRuntimeCheckResult(req.$projectVersion._id, req.query.rule);
    res.json(result);
  })().catch((err) => {
    next(new PhoenixError(err));
  });
}

function searchFiles(req, res, next) {
  (async () => {
    const result = await files.searchFiles(req.$me, req.$project, req.$projectVersion, req.query.searchContent, {
      ignoreCase: req.query.matchCase === '1',
      matchWholeWord: req.query.matchWholeWord === '1',
    });
    res.json(result);
  })().catch((err) => {
    next(new PhoenixError(err));
  });
}
/**
 * Export model definition object.
 */
module.exports = (app, prefix) => {
  const allFilesURL = `${prefix}/project-versions/:projectVersionId/files.json`;
  const subFilesURL = `${prefix}/files/:fileId/files.json`; // 批量添加文件url
  const subFileURL = `${prefix}/files/:fileId/file.json`; // 单个添加/修改文件url
  const shieldFilesURL = `${prefix}/files/shieldFile/:fileId.json`; // 屏蔽文件
  const fileURL = `${prefix}/files/:fileId.json`;
  const fileChildrenURL = `${prefix}/files/:fileId/children.json`;
  const fileTreeURL = `${prefix}/files/:fileId/tree.json`;
  const fileTreeAllURL = `${prefix}/files/:fileId/tree-all.json`;
  const fileDefectTreeURL = `${prefix}/files/:fileId/defect-tree.json`;
  const fileDiagURL = `${prefix}/files/:fileId/diag.json`;
  const typesURL = `${prefix}/files/:fileId/types.json`;
  const typeNamesURL = `${prefix}/files/:fileId/type-names.json`;
  const globalsURL = `${prefix}/files/:fileId/globals.json`;
  const literalsURL = `${prefix}/files/:fileId/literals.json`;
  const macrosURL = `${prefix}/files/:fileId/macros.json`;
  const allFilesOverviewUrl = `${prefix}/project-versions/:projectVersionId/files/overview.json`;
  const downloadFilesOverviewUrl = `${prefix}/project-versions/:projectVersionId/files/overview.xlsx`;
  const fileDefectRulesURL = `${prefix}/files/:fileId/defects/rules.json`;
  const filesAnalyzeURL = `${prefix}/project-versions/:projectVersionId/static-analyze.json`;
  const filesRegressionAnalyzeURL = `${prefix}/project-versions/:projectVersionId/static-analyze-regression.json`;
  const resetFileURL = `${prefix}/files/:fileId/reset.json`;
  const fileContentURL = `${prefix}/files/:fileId/content`;
  const fileEncodingURL = `${prefix}/files/:fileId/encoding`;
  const runtimeCheckUrl = `${prefix}/project-versions/:projectVersionId/runtime-check.json`;
  const upload = uploadProgress;
  const directoriesURL = `${prefix}/project-versions/:projectVersionId/directories.json`;
  const searchFilesURL = `${prefix}/project-versions/:projectVersionId/files/search.json`;

  app.get(fileDefectRulesURL, middleware.user.requireTokenUnexpired);
  app.get(fileDefectRulesURL, middleware.user.requireAvailable);
  app.get(fileDefectRulesURL, middleware.user.requireTester);
  app.get(fileDefectRulesURL, middleware.file.requireFileExist);
  app.get(fileDefectRulesURL, middleware.project.requireProjectAccess);
  app.get(fileDefectRulesURL, getDefectsRules);

  // 获取文件信息
  app.get(fileURL, middleware.user.requireTokenUnexpired);
  app.get(fileURL, middleware.user.requireAvailable);
  app.get(fileURL, middleware.user.requireTester);
  app.get(fileURL, middleware.file.requireFileExist);
  app.get(fileURL, middleware.user.getSuperUser);
  app.get(fileURL, middleware.project.requireProjectAccess);
  app.get(fileURL, middleware.file.getFile);

  // 获取文件内容
  app.post(fileContentURL, middleware.user.requireTokenUnexpired);
  app.post(fileContentURL, middleware.user.requireAvailable);
  app.post(fileContentURL, middleware.user.requireTester);
  app.post(fileContentURL, middleware.file.requireFileExist);
  app.post(fileContentURL, middleware.user.getSuperUser);
  app.post(fileContentURL, middleware.project.requireProjectAccess);
  app.post(fileContentURL, middleware.file.getFileContent);

  // 更新文件编码格式并返回新编码格式的文件数据
  app.put(fileEncodingURL, middleware.user.requireTokenUnexpired);
  app.put(fileEncodingURL, middleware.user.requireAvailable);
  app.put(fileEncodingURL, middleware.user.requireTester);
  app.put(fileEncodingURL, middleware.file.requireFileExist);
  app.put(fileEncodingURL, middleware.user.getSuperUser);
  app.put(fileEncodingURL, middleware.project.requireProjectAccess);
  app.put(fileEncodingURL, updateFileEncoding);
  app.put(fileEncodingURL, middleware.file.getFileContent);

  // 获取子目录/文件列表
  app.get(fileChildrenURL, middleware.user.requireTokenUnexpired);
  app.get(fileChildrenURL, middleware.user.requireAvailable);
  app.get(fileChildrenURL, middleware.user.requireTester);
  app.get(fileChildrenURL, middleware.file.requireFileExist);
  app.get(fileChildrenURL, middleware.project.requireProjectAccess);
  app.get(fileChildrenURL, middleware.file.getFileChildren);

  // 获取目录树结构
  app.get(fileTreeURL, middleware.user.requireTokenUnexpired);
  app.get(fileTreeURL, middleware.user.requireAvailable);
  app.get(fileTreeURL, middleware.user.requireTester);
  app.get(fileTreeURL, middleware.file.requireFileExist);
  app.get(fileTreeURL, middleware.project.requireProjectAccess);
  app.get(fileTreeURL, middleware.file.getFileTree);

  // 获取目录树结构（包含函数）
  app.get(fileTreeAllURL, middleware.user.requireTokenUnexpired);
  app.get(fileTreeAllURL, middleware.user.requireAvailable);
  app.get(fileTreeAllURL, middleware.user.requireTester);
  app.get(fileTreeAllURL, middleware.file.requireFileExist);
  app.get(fileTreeAllURL, middleware.project.requireProjectAccess);
  app.get(fileTreeAllURL, middleware.file.getFileTreeAll);

  // 获取目录树结构 (包含缺陷)
  app.get(fileDefectTreeURL, middleware.user.requireTokenUnexpired);
  app.get(fileDefectTreeURL, middleware.user.requireAvailable);
  app.get(fileDefectTreeURL, middleware.user.requireTester);
  app.get(fileDefectTreeURL, middleware.file.requireFileExist);
  app.get(fileDefectTreeURL, middleware.project.requireProjectAccess);
  app.get(fileDefectTreeURL, middleware.file.getFileDefectTree);

  // 添加文件/文件夹
  app.post(subFileURL, middleware.user.requireTokenUnexpired);
  app.post(subFileURL, middleware.user.requireAvailable);
  app.post(subFileURL, middleware.user.requireTester);
  app.post(subFileURL, middleware.file.requireFileExist);
  app.post(subFileURL, middleware.user.checkVersionLock);
  app.post(subFileURL, middleware.project.requireProjectAccess);
  app.post(subFileURL, middleware.project.requireProjectAvailable);
  app.post(subFileURL, middleware.projectVersion.requireProjectVersionAvailable);
  app.post(subFileURL, middleware.file.requireDirectory);
  app.post(subFileURL, middleware.progressNotify());
  app.post(subFileURL, upload.single('file'));
  app.post(subFileURL, middleware.user.getLockByVersion({ enabled: true, expireSec: 300 }));
  app.post(subFileURL, middleware.file.addFile);
  app.post(subFileURL, middleware.file.updateFiles);

  // 批量添加文件
  app.post(subFilesURL, middleware.user.requireTokenUnexpired);
  app.post(subFilesURL, middleware.user.requireAvailable);
  app.post(subFilesURL, middleware.user.requireTester);
  app.post(subFilesURL, middleware.file.requireFileExist);
  app.post(subFilesURL, middleware.user.checkVersionLock);
  app.post(subFilesURL, middleware.project.requireProjectAccess);
  app.post(subFilesURL, middleware.project.requireProjectAvailable);
  app.post(subFilesURL, middleware.projectVersion.requireProjectVersionAvailable);
  app.post(subFilesURL, middleware.file.requireDirectory);
  app.post(subFilesURL, middleware.progressNotify());
  app.post(subFilesURL, upload.array('files'));
  app.post(subFilesURL, middleware.user.getLockByVersion({ enabled: true, expireSec: 300 }));
  app.post(subFilesURL, middleware.file.addFiles);

  // 更新文件/文件夹
  app.put(subFileURL, middleware.user.requireTokenUnexpired);
  app.put(subFileURL, middleware.user.requireAvailable);
  app.put(subFileURL, middleware.user.requireTester);
  app.put(subFileURL, middleware.file.requireFileExist);
  app.put(subFileURL, middleware.user.checkVersionLock);
  app.put(subFileURL, middleware.project.requireProjectAccess);
  app.put(subFileURL, middleware.project.requireProjectAvailable);
  app.put(subFileURL, middleware.projectVersion.requireProjectVersionAvailable);
  app.put(subFileURL, middleware.progressNotify());
  app.put(subFileURL, upload.single('file'));
  app.put(subFileURL, middleware.user.getLockByVersion({ enabled: true, expireSec: 300 }));
  app.put(subFileURL, middleware.file.updateFiles);

  // 删除文件/文件夹
  app.delete(fileURL, middleware.user.requireTokenUnexpired);
  app.delete(fileURL, middleware.user.requireAvailable);
  app.delete(fileURL, middleware.user.requireTester);
  app.delete(fileURL, middleware.file.requireFileExist);
  app.delete(fileURL, middleware.user.getLockByVersion({ enabled: true, expireSec: 300 }));
  app.delete(fileURL, middleware.project.requireProjectAccess);
  app.delete(fileURL, middleware.project.requireProjectAvailable);
  app.delete(fileURL, middleware.projectVersion.requireProjectVersionAvailable);
  app.delete(fileURL, middleware.file.removeFile);

  // 编辑项目文件
  app.put(fileURL, middleware.user.requireTokenUnexpired);
  app.put(fileURL, middleware.user.requireAvailable);
  app.put(fileURL, middleware.user.requireTester);
  app.put(fileURL, middleware.file.requireFileExist);
  app.put(fileURL, middleware.user.getLockByVersion({ enabled: true, expireSec: 300 }));
  app.put(fileURL, middleware.project.requireProjectAccess);
  app.put(fileURL, middleware.project.requireProjectAvailable);
  app.put(fileURL, middleware.projectVersion.requireProjectVersionAvailable);
  app.put(fileURL, middleware.file.editFile);

  // 重置文件/文件夹，重置为未解析状态
  app.post(resetFileURL, middleware.user.requireTokenUnexpired);
  app.post(resetFileURL, middleware.user.requireAvailable);
  app.post(resetFileURL, middleware.user.requireTester);
  app.post(resetFileURL, middleware.file.requireFileExist);
  app.post(resetFileURL, middleware.user.getLockByVersion({ enabled: true, expireSec: 300 }));
  app.post(resetFileURL, middleware.project.requireProjectAccess);
  app.post(resetFileURL, middleware.project.requireProjectAvailable);
  app.post(resetFileURL, middleware.projectVersion.requireProjectVersionAvailable);
  app.post(resetFileURL, resetFile);

  // 屏蔽文件
  app.put(shieldFilesURL, middleware.user.requireTokenUnexpired);
  app.put(shieldFilesURL, middleware.user.requireAvailable);
  app.put(shieldFilesURL, middleware.user.requireTester);
  app.put(shieldFilesURL, middleware.file.requireFileExist);
  app.put(shieldFilesURL, middleware.user.getLockByVersion());
  app.put(shieldFilesURL, middleware.project.requireProjectAccess);
  app.put(shieldFilesURL, middleware.project.requireProjectAvailable);
  app.put(shieldFilesURL, middleware.projectVersion.requireProjectVersionAvailable);
  app.put(shieldFilesURL, shieldFiles);

  // 解析源码
  app.post(allFilesURL, middleware.license.detectSystemTimeTampering);
  app.post(allFilesURL, middleware.user.requireTokenUnexpired);
  app.post(allFilesURL, middleware.user.requireAvailable);
  app.post(allFilesURL, middleware.user.requireTester);
  app.post(allFilesURL, middleware.projectVersion.requireProjectVersionExist);
  app.post(allFilesURL, middleware.user.getLockByVersion());
  app.post(allFilesURL, middleware.project.requireProjectAccess);
  app.post(allFilesURL, middleware.projectVersion.requireProjectVersionAvailable);
  app.post(allFilesURL, middleware.project.requireProjectAvailable);
  app.post(allFilesURL, middleware.file.parseFileListQuery);
  app.post(allFilesURL, (req, res, next) => {
    req.body.force = true; // 强制重新解析
    next();
  });
  app.post(allFilesURL, middleware.file.getFiles);
  app.post(allFilesURL, parseFiles);

  // 静态分析
  app.post(filesAnalyzeURL, middleware.license.detectSystemTimeTampering);
  app.post(filesAnalyzeURL, middleware.user.requireTokenUnexpired);
  app.post(filesAnalyzeURL, middleware.user.requireAvailable);
  app.post(filesAnalyzeURL, middleware.user.requireTester);
  app.post(filesAnalyzeURL, middleware.projectVersion.requireProjectVersionExist);
  app.post(filesAnalyzeURL, middleware.user.getLockByVersion());
  app.post(filesAnalyzeURL, middleware.project.requireProjectAccess);
  app.post(filesAnalyzeURL, middleware.projectVersion.requireProjectVersionAvailable);
  app.post(filesAnalyzeURL, middleware.project.requireProjectAvailable);
  app.post(filesAnalyzeURL, middleware.projectVersion.requireAnalyzeTemplateExist);
  app.post(filesAnalyzeURL, middleware.file.parseFileListQuery);
  app.post(filesAnalyzeURL, middleware.file.getFiles);
  app.post(filesAnalyzeURL, analyseFiles);

  // 一键回归版本
  app.post(filesRegressionAnalyzeURL, middleware.license.detectSystemTimeTampering);
  app.post(filesRegressionAnalyzeURL, middleware.user.requireTokenUnexpired);
  app.post(filesRegressionAnalyzeURL, middleware.user.requireAvailable);
  app.post(filesRegressionAnalyzeURL, middleware.user.requireTester);
  app.post(filesRegressionAnalyzeURL, middleware.projectVersion.requireProjectVersionExist);
  app.post(filesRegressionAnalyzeURL, middleware.user.getLockByVersion());
  app.post(filesRegressionAnalyzeURL, middleware.project.requireProjectAccess);
  app.post(filesRegressionAnalyzeURL, middleware.projectVersion.requireProjectVersionAvailable);
  app.post(filesRegressionAnalyzeURL, middleware.project.requireProjectAvailable);
  app.post(filesRegressionAnalyzeURL, middleware.projectVersion.requireAnalyzeTemplateExist);
  app.post(filesRegressionAnalyzeURL, middleware.file.parseFileListQuery);
  app.post(filesRegressionAnalyzeURL, analyzeRegressionFiles);

  // 获取文件编译信息
  app.get(fileDiagURL, middleware.user.requireTokenUnexpired);
  app.get(fileDiagURL, middleware.user.requireAvailable);
  app.get(fileDiagURL, middleware.user.requireTester);
  app.get(fileDiagURL, middleware.file.requireFileExist);
  app.get(fileDiagURL, middleware.user.getSuperUser);
  app.get(fileDiagURL, middleware.project.requireProjectAccess);
  app.get(fileDiagURL, getFileDiag);

  // 获取类型系统
  app.get(typesURL, middleware.user.requireTokenUnexpired);
  app.get(typesURL, middleware.user.requireAvailable);
  app.get(typesURL, middleware.user.requireTester);
  app.get(typesURL, middleware.file.requireFileExist);
  app.get(typesURL, middleware.project.requireProjectAccess);
  app.get(typesURL, getTypes);

  // 获取类型名称集合
  app.get(typeNamesURL, middleware.user.requireTokenUnexpired);
  app.get(typeNamesURL, middleware.user.requireAvailable);
  app.get(typeNamesURL, middleware.user.requireTester);
  app.get(typeNamesURL, middleware.file.requireFileExist);
  app.get(typeNamesURL, middleware.project.requireProjectAccess);
  app.get(typeNamesURL, getTypeNames);

  // 获取全局变量
  app.get(globalsURL, middleware.user.requireTokenUnexpired);
  app.get(globalsURL, middleware.user.requireAvailable);
  app.get(globalsURL, middleware.user.requireTester);
  app.get(globalsURL, middleware.file.requireFileExist);
  app.get(globalsURL, middleware.project.requireProjectAccess);
  app.get(globalsURL, getGlobalVariables);

  // 获取字面量
  app.get(literalsURL, middleware.user.requireTokenUnexpired);
  app.get(literalsURL, middleware.user.requireAvailable);
  app.get(literalsURL, middleware.user.requireTester);
  app.get(literalsURL, middleware.file.requireFileExist);
  app.get(literalsURL, middleware.project.requireProjectAccess);
  app.get(literalsURL, getLiterals);

  // 获取宏替换信息
  app.get(macrosURL, middleware.user.requireTokenUnexpired);
  app.get(macrosURL, middleware.user.requireAvailable);
  app.get(macrosURL, middleware.user.requireTester);
  app.get(macrosURL, middleware.file.requireFileExist);
  app.get(macrosURL, middleware.project.requireProjectAccess);
  app.get(macrosURL, getMacros);

  // 项目信息总览-文件列表
  app.get(allFilesOverviewUrl, middleware.user.requireTokenUnexpired);
  app.get(allFilesOverviewUrl, middleware.user.requireAvailable);
  app.get(allFilesOverviewUrl, middleware.user.requireTester);
  app.get(allFilesOverviewUrl, middleware.projectVersion.requireProjectVersionExist);
  app.get(allFilesOverviewUrl, middleware.project.requireProjectAccess);
  app.get(allFilesOverviewUrl, allFilesOverview);

  // 项目信息总览-文件列表下载xlsx文件
  app.get(downloadFilesOverviewUrl, middleware.user.requireTokenUnexpired);
  app.get(downloadFilesOverviewUrl, middleware.user.requireAvailable);
  app.get(downloadFilesOverviewUrl, middleware.user.requireTester);
  app.get(downloadFilesOverviewUrl, middleware.projectVersion.requireProjectVersionExist);
  app.get(downloadFilesOverviewUrl, middleware.project.requireProjectAccess);
  app.get(downloadFilesOverviewUrl, exportFilesOverview);

  // 创建多层文件目录(暂为614所用）
  app.post(directoriesURL, middleware.user.requireTokenUnexpired);
  app.post(directoriesURL, middleware.user.requireAvailable);
  app.post(directoriesURL, middleware.user.requireTester);
  app.post(directoriesURL, middleware.projectVersion.requireProjectVersionExist);
  app.post(directoriesURL, middleware.user.getLockByVersion({ enabled: true, expireSec: 300 }));
  app.post(directoriesURL, middleware.project.requireProjectAccess);
  app.post(directoriesURL, createDirectories);

  // 运行时检查
  app.post(runtimeCheckUrl, middleware.license.detectSystemTimeTampering);
  app.post(runtimeCheckUrl, middleware.user.requireTokenUnexpired);
  app.post(runtimeCheckUrl, middleware.user.requireAvailable);
  app.post(runtimeCheckUrl, middleware.user.requireTester);
  app.post(runtimeCheckUrl, middleware.projectVersion.requireProjectVersionExist);
  app.post(runtimeCheckUrl, middleware.user.getLockByVersion());
  app.post(runtimeCheckUrl, middleware.project.requireProjectAccess);
  app.post(runtimeCheckUrl, middleware.projectVersion.requireProjectVersionAvailable);
  app.post(runtimeCheckUrl, middleware.project.requireProjectAvailable);
  app.post(runtimeCheckUrl, runTimeCheck);
  // 获取运行时检查
  app.get(runtimeCheckUrl, middleware.license.detectSystemTimeTampering);
  app.get(runtimeCheckUrl, middleware.user.requireTokenUnexpired);
  app.get(runtimeCheckUrl, middleware.user.requireAvailable);
  app.get(runtimeCheckUrl, middleware.user.requireTester);
  app.get(runtimeCheckUrl, middleware.projectVersion.requireProjectVersionExist);
  app.get(runtimeCheckUrl, middleware.user.getLockByVersion());
  app.get(runtimeCheckUrl, middleware.project.requireProjectAccess);
  app.get(runtimeCheckUrl, middleware.projectVersion.requireProjectVersionAvailable);
  app.get(runtimeCheckUrl, middleware.project.requireProjectAvailable);
  app.get(runtimeCheckUrl, getRuntimeCheckResult);

  // 搜索文件内容
  app.get(searchFilesURL, middleware.user.requireTokenUnexpired);
  app.get(searchFilesURL, middleware.user.requireAvailable);
  app.get(searchFilesURL, middleware.user.requireTester);
  app.get(searchFilesURL, middleware.projectVersion.requireProjectVersionExist);
  app.get(searchFilesURL, middleware.project.requireProjectAccess);
  app.get(searchFilesURL, searchFiles);
};
